use std::fs::File;
use std::io;
use std::io::{BufRead, BufReader};
use std::time::Duration;

use resolve_path::PathResolveExt;
use serde::Deserialize;
use tokio::sync::mpsc;
use walkdir::WalkDir;

#[tauri::command]
pub async fn start_search(search_option: SearchOption, window: tauri::Window) -> Result<(), String> {
    let (tx, mut rx) = mpsc::channel(100);
    tokio::spawn(async move {
        search_files(search_option, tx).await.unwrap();
    });
    while let Some(result) = rx.recv().await {
        window.eval(&format!("window.searchResult('{}')", result)).unwrap();
    }
    Ok(())
}

#[tauri::command]
pub fn test_async_log(window: tauri::Window) {
    tauri::async_runtime::spawn(async move {
        let mut count = 0;
        loop {
            if count > 10 {
                break;
            }
            // 每隔5秒发送一次消息
            tokio::time::sleep(Duration::from_secs(5)).await;
            let message = format!("Message number: {}", count);
            count += 1;
            window.emit("timed-event", message).unwrap();
        }
    });
}

#[derive(Debug, Deserialize)]
pub struct SearchOption {
    path: Vec<String>,
    include_name: Option<Vec<String>>,
    exclude_name: Option<Vec<String>>,
    include_content: Option<Vec<String>>,
}

async fn search_files(
    search_option: SearchOption,
    sender: mpsc::Sender<String>,
) -> io::Result<()> {
    for dir in search_option.path {
        for entry in WalkDir::new(dir.resolve()) {
            let entry = entry?;
            if entry.file_type().is_file() {
                let file_path = entry.path();
                if let Some(include_name) = &search_option.include_name {
                    if !include_name.iter().any(|name| file_path.to_string_lossy().contains(name)) {
                        continue;
                    }
                }
                if let Some(exclude_name) = &search_option.exclude_name {
                    if exclude_name.iter().any(|name| file_path.to_string_lossy().contains(name)) {
                        continue;
                    }
                }
                if let Some(include_content) = &search_option.include_content {
                    let file = File::open(file_path)?;
                    let reader = BufReader::new(file);
                    for line in reader.lines() {
                        let line = line?;
                        let line = String::from_utf8_lossy(line.as_bytes());
                        if include_content.iter().all(|content| line.contains(content)) {
                            let msg = format!("Found in {:?}: {}", file_path, line);
                            println!("msg:{msg}");
                            sender.send(msg).await.unwrap();
                        }
                    }
                }
            }
        }
    }
    Ok(())
}